﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using JBeamLibrary.VehicleParts.Elements;

namespace JBeamLibrary.VehicleParts
{
    public class VehicleConfig : KeyedCollection<string, KeyValuePair<Slot, VehiclePart>>
    {
        #region Properties

        /// <summary>Gets the vehicle this config relates to</summary>
        public Vehicle Parent
        {
            get;
            private set;
        }

        /// <summary>Gets or sets the config file name</summary>
        public string FileName
        {
            get;
            set;
        }

        /// <summary>Gets the full path of the config file</summary>
        public string FilePath
        {
            get { return string.Format(@"{0}\{1}", Parent.Folder, FileName); }
        }

        /// <summary>Gets the display name</summary>
        public string DisplayName
        {
            get;
            set;
        }

        #endregion

        #region CTORs

        public VehicleConfig()
        {
            
        }

        public VehicleConfig(Vehicle vehicle, string fileName)
        {
            Parent = vehicle;
            FileName = fileName;
        }

        #endregion

        #region Methods

        /// <summary>(Re-)loads the contents of the config file</summary>
        /// <returns></returns>
        public bool Load()
        {
            /* Need a file name ffs */
            return !string.IsNullOrEmpty(FileName) && LoadFromFile(FileName);
        }

        /// <summary>Loads the contents of a config file</summary>
        /// <param name="fileName"></param>
        public bool LoadFromFile(string fileName)
        {
            /* Variables */
            var filePath = string.Format(@"{0}\{1}", Parent.Folder, fileName);
            if (!filePath.ToLowerInvariant().EndsWith(".pc")) filePath += ".pc";

            /* Check that the file exists */
            if (!File.Exists(filePath)) return false;

            /* Read whole file text */
            var text = File.ReadAllText(filePath, Encoding.Default);

            /* Remove unneeded characters */
            text = Regex.Replace(text, @"[{} \t\r\n""]", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Multiline);

            /* Split key / values */
            var pairs = text.Split(',').Where(line => !string.IsNullOrEmpty(line)).Select(line => new KeyValuePair<string, string>(line.Split('=')[0], line.Split('=')[1]));

            /* Update list */
            ClearItems();
            foreach (var pair in pairs)
            {
                var slot = Parent.FindSlot(pair.Key);
                if (slot == null)
                {
                    Parent.ErrorManager.AddError(fileName, string.Format("Configuration slot not found in vehicle '{0}': '{1}'", Parent.Label, pair.Key));
                    continue;
                }
                var part = Parent.FindPart(pair.Value);
                Add(new KeyValuePair<Slot, VehiclePart>(slot, part));
            }

            /* All good, just replace the file name with the new one and return true */
            FileName = fileName;

            /* Load the display name */
            LoadDescription();

            /* Return */
            return true;
        }

        public bool LoadDescription()
        {
            /* Variables */
            var fileName = FileName;
            if (!fileName.ToLowerInvariant().EndsWith(".pc")) fileName += ".pc";
            var filePath = string.Format(@"{0}\{1}.cs", Parent.Folder, fileName);

            /* Check that the file exists */
            if (!File.Exists(filePath)) return false;

            /* Read whole file text */
            var lines = File.ReadAllLines(filePath, Encoding.Default);

            /* Find the right line */
            foreach (var line in lines)
            {
                var match = Regex.Match(line, @"%configName\s*=\s*""(.*)""");
                if (match.Success)
                {
                    DisplayName = match.Groups[1].Value;
                    return true;
                }
            }

            return false;
        }

        /// <summary>Saves the contents of the config</summary>
        public void Save(bool compress = true)
        {
            SaveToFile(FileName, compress);
        }

        /// <summary>Saves the contents of the config to the specified file</summary>
        /// <param name="fileName"></param>
        /// <param name="compress"></param>
        public void SaveToFile(string fileName, bool compress = true)
        {
            /* Variables */
            var filePath = string.Format(@"{0}\{1}", Parent.Folder, fileName);
            if (!filePath.ToLowerInvariant().EndsWith(".pc")) filePath += ".pc";

            /* Prepare the text */
            var builder = new StringBuilder();
            builder.Append("{");
            foreach (var pair in this)
            {
                builder.AppendFormat(
                    @"{2}{0}=""{1}"",",
                    pair.Key.TypeName,
                    pair.Value != null ? pair.Value.Name : "none",
                    (compress ? string.Empty : Environment.NewLine + "\t"));
            }
            builder.AppendFormat(@"{0}}}", (compress ? string.Empty : Environment.NewLine));

            /* Drop the file if it exists */
            if (File.Exists(filePath)) File.Delete(filePath);

            /* Write new contents */
            File.WriteAllText(filePath, builder.ToString(), Encoding.Default);

            /* Save display name */
            SaveDescription();
        }

        public void SaveDescription()
        {
            /* Variables */
            var fileName = FileName;
            if (!fileName.ToLowerInvariant().EndsWith(".pc")) fileName += ".pc";
            var filePath = string.Format(@"{0}\{1}.cs", Parent.Folder, fileName);
            var lines = new[] { string.Format(@"%configName = ""{0}"";", DisplayName) };
            File.WriteAllLines(filePath, lines);
        }

        #endregion

        #region KeyedCollection

        protected override string GetKeyForItem(KeyValuePair<Slot, VehiclePart> item)
        {
            return item.Key.TypeName;
        }

        #endregion
    }
}
